package com.im;

import com.common.InputBox;

import java.awt.BorderLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.HashMap;
import java.util.Map;

import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JToolBar;

// 主窗口
@SuppressWarnings("serial")
class MainWindow extends JFrame implements ActionListener, ChatWindow.Callback, Client.Callback, MouseListener {
    private final JButton mButtonAddFriend;         // "添加好友"按钮
    private final JButton mButtonLogoff;            // "离线"按钮
    private final JButton mButtonLogon;             // "登录"按钮
    private final JButton mButtonMChat;             // "群发消息"按钮
    private final JButton mButtonReg;               // "注册"按钮
    private final Map<String, ChatWindow> mChats;   // 聊天窗口集合
    private Client mClient;                         // 客户端
    private final JLabel mLabelFriendCount;         // "好友数"标签
    private final JLabel mLabelStatus;              // "登录状态"标签
    private final UserListView mListViewUsers;      // 好友列表控件

    /**
     * 构造方法。
     */
    public MainWindow() {
        // 设置当单击右上角的X按钮时退出程序
        super.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        
        // 设置窗口标题
        super.setTitle(Const.getString("IDS_APP_NAME"));

        // 设置窗口尺寸不能改变
        super.setResizable(false);

        // 设置窗口尺寸
        super.setSize(Const.WIDTH, Const.HEIGHT);

        // 设置窗口居中
        super.setLocationRelativeTo(null);

        // 监听窗口事件
        super.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                // 关闭客户端
                mClient.close();
            }
        });
        
        // 添加工具栏
        final JToolBar toolbar = new JToolBar();
        toolbar.setFloatable(false);
        super.add(toolbar, BorderLayout.NORTH);

        // 设置"登录"按钮
        mButtonLogon = new JButton(new ImageIcon(Const.BUTTON_LOGON_IMAGE_PATH));
        mButtonLogon.setToolTipText(Const.getString("IDS_LOGON"));
        mButtonLogon.setFocusable(false);
        mButtonLogon.setBorderPainted(false);
        mButtonLogon.addActionListener(this);
        toolbar.add(mButtonLogon);
        
        // 设置"注册"按钮
        mButtonReg = new JButton(new ImageIcon(Const.BUTTON_REG_IMAGE_PATH));
        mButtonReg.setToolTipText(Const.getString("IDS_REG"));
        mButtonReg.setFocusable(false);
        mButtonReg.setBorderPainted(false);
        mButtonReg.addActionListener(this);
        toolbar.add(mButtonReg);

        // 设置"添加好友"按钮
        mButtonAddFriend = new JButton(new ImageIcon(Const.BUTTON_ADD_FRIEND_IMAGE_PATH));
        mButtonAddFriend.setEnabled(false);
        mButtonAddFriend.setToolTipText(Const.getString("IDS_ADD_FRIEND"));
        mButtonAddFriend.setFocusable(false);
        mButtonAddFriend.setBorderPainted(false);
        mButtonAddFriend.addActionListener(this);
        toolbar.add(mButtonAddFriend);

        // 设置"群发消息"按钮
        mButtonMChat = new JButton(new ImageIcon(Const.BUTTON_MCHAT_IMAGE_PATH));
        mButtonMChat.setEnabled(false);
        mButtonMChat.setToolTipText(Const.getString("IDS_MCHAT"));
        mButtonMChat.setFocusable(false);
        mButtonMChat.setBorderPainted(false);
        mButtonMChat.addActionListener(this);
        toolbar.add(mButtonMChat);
        
        // 设置"注销"按钮
        mButtonLogoff = new JButton(new ImageIcon(Const.BUTTON_LOGOFF_IMAGE_PATH));
        mButtonLogoff.setEnabled(false);
        mButtonLogoff.setToolTipText(Const.getString("IDS_LOGOFF"));
        mButtonLogoff.setFocusable(false);
        mButtonLogoff.setBorderPainted(false);
        mButtonLogoff.addActionListener(this);
        toolbar.add(mButtonLogoff);

        // 创建好友列表控件
        mListViewUsers = new UserListView();
        mListViewUsers.addMouseListener(this);
        super.add(mListViewUsers);

        // 创建状态栏
        final JToolBar statusbar = new JToolBar();
        final GridBagLayout gbl = new GridBagLayout();
        statusbar.setLayout(gbl);
        statusbar.setFloatable(false);
        super.add(statusbar, BorderLayout.SOUTH);

        final GridBagConstraints gbc = new GridBagConstraints();
        gbc.fill = GridBagConstraints.HORIZONTAL;
        gbc.weightx = 1;        

        // 添加"登录状态"标签
        mLabelStatus = new JLabel(Const.getString("IDS_STATUS_LOGOFF"));
        mLabelStatus.setBorder(BorderFactory.createEtchedBorder());
        gbl.setConstraints(mLabelStatus, gbc);
        statusbar.add(mLabelStatus);

        // 添加"好友数"标签
        mLabelFriendCount = new JLabel(String.format(Const.getString("IDS_FRIEND_COUNT"), 0));
        mLabelFriendCount.setBorder(BorderFactory.createEtchedBorder());
        gbl.setConstraints(mLabelFriendCount, gbc);
        statusbar.add(mLabelFriendCount);
        
        // 初始化成员
        mChats = new HashMap<String, ChatWindow>();
        
        // 创建客户端
        try {
            mClient = new Client(this);
        } catch (Exception e) {
            JOptionPane.showMessageDialog(this, this.getResultMessage(ResultCode.NETWORK_ERROR), " ", JOptionPane.ERROR_MESSAGE);
            System.exit(0);
        }
    }

    /**
     * 按钮的单击响应方法。
     * @param e 事件相关信息
     */
    @Override
    public void actionPerformed(ActionEvent e) {
        final Object button = e.getSource();
        if (button == mButtonLogon) {
            this.onButtonLogonClicked();
        } else if (button == mButtonReg) {
            this.onButtonRegClicked();
        } else if (button == mButtonAddFriend) {
            this.onButtonAddFriendClicked();
        } else if (button == mButtonMChat) {
            this.onButtonMChatClicked();
        } else if (button == mButtonLogoff) {
            this.onButtonLogoffClicked();
        }
    }

    /**
     * 添加所有好友到好友列表控件中。
     * @param result    登录结果
     */
    private void addAllFriends(LogonResult result) {
        for (int i = 0; i < result.mFriendCount; i++) {
            this.addOneFriend(result.mFriends.get(i).mUsername, result.mFriends.get(i).mIconIndex, result.mFriendsOnline.get(i));
        }

        mLabelFriendCount.setText(String.format(Const.getString("IDS_FRIEND_COUNT"), result.mFriendCount));
    }
    
    /**
     * 添加一个好友到好友列表控件中。
     * @param friendName    好友名
     * @param iconIndex     好友头像索引
     * @param isOnline      好友在线则为 true，否则为 false
     */
    private void addOneFriend(String friendName, int iconIndex, boolean isOnline) {
        if (iconIndex < 0) {
            return;
        }
        mListViewUsers.addItem(friendName, iconIndex, isOnline);
    }

    /**
     * 改变界面状态。
     * @param isLogon   已登录则为 true，否则为 false
     */
    private void changeState(boolean isLogon) {
        mButtonLogon.setEnabled(!isLogon);
        mButtonReg.setEnabled(!isLogon);
        mButtonAddFriend.setEnabled(isLogon);
        mButtonMChat.setEnabled(isLogon);
        mButtonLogoff.setEnabled(isLogon);

        String text;
        if (isLogon) {
            text = Const.getString("IDS_STATUS_LOGON");
            mLabelStatus.setText(text);
        } else {
            text = Const.getString("IDS_STATUS_LOGOFF");
            mLabelStatus.setText(text);
        }
        text = String.format(Const.getString("IDS_FRIEND_COUNT"), 0);
        mLabelFriendCount.setText(text);
    }
    
    /**
     * 清除所有聊天窗口。
     */
    private void clearChatWindow() {
        for (ChatWindow chatWindow: mChats.values()) {
            chatWindow.dispose();
        }
        mChats.clear();
    }
    
    /**
     * 获取指定好友名对应的聊天窗口。
     * @param friendName    好友名
     * @return 好友名对应的聊天窗口
     */
    private ChatWindow getChatWindow(String friendName) {
        // 查找用户名对应的聊天窗口
        ChatWindow window = mChats.get(friendName);

        // 如果未找到，则新建一个
        if (window == null) {
            window = new ChatWindow(this, this, friendName);
            mChats.put(friendName, window);
        }

        return window;
    }

    
    /**
     * 获取结果信息。
     * @param resultCode    结果码
     * @return 结果信息
     */
    private String getResultMessage(ResultCode resultCode) {
        switch (resultCode) {
            case ADD_FRIEND_ALLOW:
                return Const.getString("IDS_ADD_FRIEND_ALLOW");
            case ADD_FRIEND_NOT_ALLOW:
                return Const.getString("IDS_ADD_FRIEND_NOT_ALLOW");
            case ALREADY_BE_FRIENDS:
                return Const.getString("IDS_ALREADY_BE_FRIENDS");
            case FRIEND_NAME_EQUAL_SELF_NAME:
                return Const.getString("IDS_FRIEND_NAME_EQUAL_SELF_NAME");
            case NETWORK_ERROR:
                return Const.getString("IDS_NETWORK_ERROR");
            case PASSWORD_WRONG:
                return Const.getString("IDS_PASSWORD_WRONG");
            case REG_SUCCEEDED:
                return Const.getString("IDS_REG_SUCCEEDED");
            case TOO_MANY_FRIENDS:
                return Const.getString("IDS_TOO_MANY_FRIENDS");
            case USER_ALREADY_LOGON:
                return Const.getString("IDS_USER_ALREADY_LOGON");
            case USER_EXISTS:
                return Const.getString("IDS_USER_EXISTS");
            case USER_NOT_FOUND:
                return Const.getString("IDS_USER_NOT_FOUND");
            default:
                break;
        }

        return "";
    }
    
    /**
     * 双击好友列表控件的响应方法。
     * @param e 事件相关信息
     */
    @Override
    public void mouseClicked(MouseEvent e) {
        if (e.getClickCount() == 2) {
            final String friendName = mListViewUsers.getSelectedValue();
            final ChatWindow chatWindow = this.getChatWindow(friendName);
            chatWindow.setVisible(true);
        }
    }

    @Override
    public void mouseEntered(MouseEvent e) {
    }

    @Override
    public void mouseExited(MouseEvent e) {
    }

    @Override
    public void mousePressed(MouseEvent e) {
    }

    @Override
    public void mouseReleased(MouseEvent e) {
    }

    /**
     * "添加好友"按钮的单击响应方法。
     */
    private void onButtonAddFriendClicked() {
        // 显示输入窗口，让用户输入好友名
        final String tipText = Const.getString("IDS_PLEASE_INPUT_USERNAME");
        final String username = InputBox.getStringValue(null, this, tipText);
        if (username == null) {
            return;
        }
        if (username.isEmpty()) {
            return;
        }

        // 执行添加好友
        final ResultCode resultCode = mClient.addFriend(username);
        if (resultCode != ResultCode.SUCCEEDED) {
            JOptionPane.showMessageDialog(this, this.getResultMessage(resultCode), " ", JOptionPane.ERROR_MESSAGE);
        }
    }
    
    /**
     * "离线"按钮的单击响应方法。
     */
    private void onButtonLogoffClicked() {
        // 设置各种控件的状态
        this.changeState(false);

        // 清空各种列表
        mListViewUsers.clear();
        this.clearChatWindow();

        // 发送离线请求
        mClient.logoff();
    }
    
    /**
     * "登录"按钮的单击响应方法。
     */
    private void onButtonLogonClicked() {
        // 显示登录窗口
        final LogonWindow logonWindow = new LogonWindow();
        logonWindow.setVisible(true);
        final LogonWindow.ClickedButton clickedButton = logonWindow.getClickedButton();
        if (clickedButton == LogonWindow.ClickedButton.OK) {
            // 登录
            mClient.logon(logonWindow.getUsername(), logonWindow.getPassword());
        }
    }

    /**
     * "群发消息"按钮的单击响应方法。
     */
    private void onButtonMChatClicked() {
        this.getChatWindow(ImProtocol.MULTI_CHAT).setVisible(true);
    }
    
    /**
     * "注册"按钮的单击响应方法。
     */
    private void onButtonRegClicked() {
        // 显示注册窗口
        final RegWindow regWindow = new RegWindow();
        regWindow.setVisible(true);
        if (regWindow.getClickedButton() == RegWindow.ClickedButton.OK) {
            // 注册
            mClient.reg(regWindow.getUsername(), regWindow.getPassword(), regWindow.getIconIndex());
        }
    }
    
    /**
     * 聊天事件的响应方法（客户端到服务器）。
     * @param chatInfo  聊天信息
     */
    @Override
    public void onChatC2S(ChatInfo chatInfo) {
        mClient.chat(chatInfo);
    }

    /**
     * 聊天事件的响应方法（服务器到客户端）。
     * @param chatInfo  聊天信息
     */
    @Override
    public void onChatS2C(ChatInfo chatInfo) {
        ChatWindow chatWindow;
        if (chatInfo.mDstUsername.equals(ImProtocol.MULTI_CHAT)) {
            chatWindow = this.getChatWindow(ImProtocol.MULTI_CHAT);
        } else {
            chatWindow = this.getChatWindow(chatInfo.mSrcUsername);
        }
        chatWindow.setContent(chatInfo);
        chatWindow.setVisible(true);
    }

    /**
     * 好友离线事件的响应方法。
     * @param request   离线请求
     */
    @Override
    public void onFriendLogoff(LogoffRequest request) {
        mListViewUsers.changeItemColor(request.mUsername, false);
    }
    
    /**
     * 好友登录事件的响应方法。
     * @param friendLogon   好友登录信息
     */
    @Override
    public void onFriendLogon(FriendLogon friendLogon) {
        mListViewUsers.changeItemColor(friendLogon.mUsername, true);
    }

    /**
     * 得到添加好友请求事件的响应方法。
     * @param request   添加好友请求
     */    
    @Override
    public void onGetAddFriendRequest(AddFriendRequest request) {
        final String message = request.mSrcUsername + Const.getString("IDS_CONFIRM_ADD_FRIEND");
        final int clickedButton = JOptionPane.showConfirmDialog(this, message, " ", JOptionPane.YES_NO_OPTION);
        final boolean allow = clickedButton == JOptionPane.YES_OPTION;
        if (allow) {
            this.addOneFriend(request.mSrcUsername, request.mSrcIconIndex, true);
            mLabelFriendCount.setText(String.format(Const.getString("IDS_FRIEND_COUNT"), mClient.getFriendCount()));
        }
        mClient.allowAddFriend(allow, request);
    }

    /**
     * 得到添加好友结果事件的响应方法。
     * @param result    结果
     */
    @Override
    public void onGetAddFriendResult(AddFriendResult result) {
        String message = this.getResultMessage(result.mResultCode);
        if (result.mResultCode == ResultCode.ADD_FRIEND_ALLOW) {
            message = String.format(message, result.mDstUsername);
            this.addOneFriend(result.mDstUsername, result.mDstIconIndex, true);
            mLabelFriendCount.setText(String.format(Const.getString("IDS_FRIEND_COUNT"), mClient.getFriendCount()));
            JOptionPane.showMessageDialog(this, message, " ", JOptionPane.INFORMATION_MESSAGE);
        } else if (result.mResultCode == ResultCode.ALREADY_BE_FRIENDS || 
            result.mResultCode == ResultCode.ADD_FRIEND_NOT_ALLOW ||
            result.mResultCode == ResultCode.USER_NOT_FOUND) {
            message = result.mDstUsername + message;
            JOptionPane.showMessageDialog(this, message, " ", JOptionPane.WARNING_MESSAGE);
        }
    }

    /**
     * 得到登录结果事件的响应方法。
     * @param result    登录结果
     */
    @Override
    public void onGetLogonResult(LogonResult result) {
        if (result.mResultCode == ResultCode.LOGON_SUCCEEDED) {
            this.changeState(true);
            this.addAllFriends(result);
        } else {
            final String message = this.getResultMessage(result.mResultCode);
            JOptionPane.showMessageDialog(this, message, " ", JOptionPane.ERROR_MESSAGE);
        }
    }

    /**
     * 得到注册结果事件的响应方法。
     * @param result    注册结果
     */
    @Override
    public void onGetRegResult(RegResult result) {
        final String message = this.getResultMessage(result.mResultCode);
        if (result.mResultCode == ResultCode.REG_SUCCEEDED) {
            this.changeState(true);
            JOptionPane.showMessageDialog(this, message, " ", JOptionPane.INFORMATION_MESSAGE);
        } else {
            JOptionPane.showMessageDialog(this, message, " ", JOptionPane.ERROR_MESSAGE);
        }
    }
}
